using System;
using System.IO;
using System.IO.Compression;

namespace WcfExtensions.ServiceModel.Channels
{
    public enum CompressionAlgorithm
    {
        GZip,
        Deflate
    }

    internal static class DataCompressor
    {
        public static byte[] Compress(byte[] decompressedData, CompressionAlgorithm algorithm, CompressionLevel level)
        {
            var memoryStream = new MemoryStream();

            switch (algorithm)
            {
                case CompressionAlgorithm.GZip:
                    var gZipStream = new GZipStream(memoryStream, CompressionMode.Compress, true);
                    gZipStream.Write(decompressedData, 0, decompressedData.Length);
                    gZipStream.Close();
                    break;
                case CompressionAlgorithm.Deflate:
                    var compressedDeflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, true);
                    compressedDeflateStream.Write(decompressedData, 0, decompressedData.Length);
                    compressedDeflateStream.Close();
                    break;
                default:
                    throw new NotSupportedException(
                        String.Format("Unknown compression algorithm parameter must be deflate or gzip: {0}", algorithm));
            }

            return memoryStream.ToArray();
        }

        private static byte[] LoadToBuffer(Stream stream)
        {
            var memStream = new MemoryStream();
            var buffer = new byte[1024];
            int length;
            while ((length = stream.Read(buffer, 0, buffer.Length)) > 0)
            {
                memStream.Write(buffer, 0, length);
            }
            return memStream.ToArray();
        }

        public static byte[] Decompress(byte[] compressedData, CompressionAlgorithm algorithm, CompressionLevel level)
        {
            var memoryStream = new MemoryStream(compressedData);
            byte[] buffer;
            switch (algorithm)
            {
                case CompressionAlgorithm.GZip:
                    using (var gZipStream = new GZipStream(memoryStream, CompressionMode.Decompress))
                    {
                        buffer = LoadToBuffer(gZipStream);
                    }
                    break;
                case CompressionAlgorithm.Deflate:
                    using (var deflateStream = new DeflateStream(memoryStream, CompressionMode.Decompress))
                    {
                        buffer = LoadToBuffer(deflateStream);
                    }
                    break;
                default:
                    throw new NotSupportedException(
                        String.Format("Unknown compression algorithm parameter must be deflate or gzip: {0}", algorithm));
            }
            return buffer;
        }
    }
}